(ns main.db
  (:use compojure.core
        [hiccup page-helpers form-helpers]
        sandbar.stateful-session
        somnium.congomongo)
  (:require [clj-time.core :as time]
            [clj-time.format :as time-format]))

(def conn 
  (make-connection "restosys"
                   :host "127.0.0.1"
                   :port 27017))

(set-connection! conn)

(defn get-date []
  (time-format/unparse (time-format/formatter "dd-MM-yyyy") (time/now)))
(defn get-time []
  (time-format/unparse (time-format/formatter "HH:mm") (time/now)))
(defn format-number [s]
  (str (format "%.2f" s)))

(defn save-user [fname lname passcode role]
  (insert! :users
           {:id (.toString (java.util.UUID/randomUUID))
            :fname fname
            :lname lname
            :passcode passcode
            :role role
            :inshift 0
            :income 0
            :visible 1
            :date-start (get-date)
            }))

(defn save-bill [id user-id]
  (insert! :bills
           {:id id
            :user-id user-id
            :printed 0
            :total 0
            :time (get-time)
            :date (get-date)}))

(defn add-article [label price instock quantity sub-category category]
    (insert! :articles
             {:label label
              :price price
              :code (.toString (java.util.UUID/randomUUID))
              :quantity quantity
              :sub-category sub-category
              :category category
              :visible 1
              :instock instock}))

(defn add-report [waiter-id waiter-name date time articles total]
  (insert! :reports
           {:waiter-id waiter-id
            :waiter-name waiter-name
            :date date
            :time time
            :articles articles
            :total total}))


(defn get-user [id]
  (fetch-one :users :where {:id id}))

(defn get-users [where]
  (fetch :users :where (merge {:visible 1} where)))

(defn get-user-by-passcode [passcode]
  (fetch-one :users :where {:passcode passcode}))

(defn get-bill [id]
  (fetch-one :bills :where {:id id}))

(defn get-bills [where]
  (fetch :bills :where where :limit 20))

(defn bills-count [where]
  (fetch-count :bills :where where))

(defn user-count [passcode]
  (fetch-count :users :where {:passcode passcode :visible 1}))

(defn users-count [where]
  (fetch-count :users :where (merge {:visible 1} where)))

(defn article-count [code]
  (fetch-count :articles :where {:code code}))

(defn articles-count [where]
  (fetch-count :articles :where where))

(defn get-article [code]
  (fetch-one :articles :where {:code code}))

(defn get-articles [there]
  (fetch :articles :where (merge {:visible 1} there)))

(defn get-article-from-bill [article-id bill-id]
  (fetch-one :billarticle :where {:article-id article-id :bill-id bill-id}))

(defn get-articles-from-bill [bill-id]
  (fetch :billarticle :where {:bill-id bill-id}))

(defn generate-report [waiter-id articles total]
  (add-report waiter-id (str ((get-user waiter-id) :fname) " " ((get-user waiter-id) :lname)) 
              (get-date) (get-time) (get-articles-from-bill articles) total))

(defn get-reports [where]
  (fetch :reports :where where))

(defn update-article [label price instock code quantity sub-category category]
  (update! :articles (get-article code) (merge (get-article code) {:label label :price price :instock instock 
                               :code code :quantity quantity :sub-category sub-category :category category})))

(defn update-user [id fname lname date-start date-end passcode role]
  (update! :users (get-user id) (merge {:id id :fname fname :lname lname :date-start date-start :date-end date-end 
                                 :passcode passcode :role role} (get-user id))))

(defn update-print-bill [id]
  (update! :users (get-user ((get-bill id) :user-id)) 
           (merge (get-user ((get-bill id) :user-id)) 
                  {:income (+ ((get-bill id) :total) ((get-user ((get-bill id) :user-id)) :income))}))
  (update! :bills (get-bill id) (merge (get-bill id) {:printed 1}))
  (generate-report ((get-bill id) :user-id) id ((get-bill id) :total)))

(defn article-increase [article-id bill-id]
  (if (number? ((get-article article-id) :instock))
  (update! :articles (get-article article-id) 
           (merge (get-article article-id) {:instock (dec ((get-article article-id) :instock))})))
  (if (< (fetch-count :billarticle :where {:article-id article-id :bill-id bill-id}) 1)
    (insert! :billarticle {:article-id article-id :bill-id bill-id :quantity 1})
    (do
      (def q (ref ((get-article-from-bill article-id bill-id) :quantity)))
      (update! :billarticle (get-article-from-bill article-id bill-id)
               {:article-id article-id :bill-id bill-id :quantity (+ @q 1)})))
  (update! :bills (get-bill bill-id) (merge (get-bill bill-id) 
                                            {:total (+ ((get-bill bill-id) :total) ((get-article article-id) :price) )})))

(defn article-decrease [article-id bill-id]
  (if (number? ((get-article article-id) :instock))
  (update! :articles (get-article article-id) 
           (merge (get-article article-id) {:instock (inc ((get-article article-id) :instock))})))
  (if (= ((get-article-from-bill article-id bill-id) :quantity) 1)
    (destroy! :billarticle {:article-id article-id :bill-id bill-id})
    (update! :billarticle (get-article-from-bill article-id bill-id)
             {:article-id article-id :bill-id bill-id :quantity 
              (- ((get-article-from-bill article-id bill-id) :quantity) 1)}))
  (update! :bills (get-bill bill-id) (merge (get-bill bill-id) 
                                            {:total (- ((get-bill bill-id) :total) ((get-article article-id) :price) )})))

(defn delete-article [code]
  (update! :articles (get-article code) (merge (get-article code) {:visible 0})))
  
(defn delete-user [id]
  (update! :users (get-user id) (merge (get-user id) {:visible 0})))

(defn delete-bill [id]
  (destroy! :bills {:id id}))

(defn start-end-shift [id]
  (if (== ((get-user id) :inshift) 0)
    (update! :users (get-user id) (merge (get-user id) {:inshift 1 :income 0}))
    (update! :users (get-user id) (merge (get-user id) {:inshift 0}))))

